`timescale 1ns / 1ps
/************************************************************\
 **  Copyright (c) 2022-2023 Gonsin, Inc.
 **  All Right Reserved.
 **  Author: http://www.anlogic.com/
 **  Description: rx_client_fifo
 **  Rev 1.0
\************************************************************/

module rx_client_fifo (
  // Local-link Interface
  input rd_clk_i,
  input rd_sreset_i,
  output reg [7:0] rddata8b_o,
  output reg rd_sofN_o,
  output rd_eofN_o,
  output reg rd_src_rdyN_o,
  input rd_dst_rdyN_i,
  output [3:0] rx4b_fifoStatus_o,

  // Client Interface
  input wr_clk_i,
  input wr_sreset_i,
  input wr_enable_i,
  input [7:0] rxdata8b_i,
  input rxdata_valid_i,
  input rx_goodFrame_i,
  input rx_badFrame_i,
  output overflow_o
);

// Encode rd_state_machine states
localparam WAIT_s = 3'b000;
localparam QUEUE1_s = 3'b001;
localparam QUEUE2_s = 3'b010;
localparam QUEUE3_s = 3'b011;
localparam QUEUE_SOF_s = 3'b100;
localparam SOF_s = 3'b101;
localparam DATA_s = 3'b110;
localparam EOF_s = 3'b111;

reg [2:0] rd3b_sm;
reg [2:0] rd3b_nxt_sm;

// Encode wr_state_machine states
localparam IDLE_s = 3'b000;
localparam FRAME_s = 3'b001;
localparam END_s = 3'b010;
localparam GF_s = 3'b011;
localparam BF_s = 3'b100;
localparam OVFLOW_s = 3'b101;

reg [2:0] wr3b_sm;
reg [2:0] wr3b_nxt_sm;

//----------------------------------------------------------------------------
// Define Internal Signals
//----------------------------------------------------------------------------
wire wr_en_w;
wire wr_enU_w;
wire wr_enL_w;

reg [11:0] wr12b_addr;
wire wr_addrInc_w;
wire wr_startAddrLoad_w;
wire wr_addrReload_w;
reg [11:0] wr12b_startAddr;
reg [7:0] wr8b_data_bram;
reg [7:0] wr8b_data_pipe[0:1];
reg [0:0] wr_eof_bram;
reg wr_dv_pipe[0:1];
reg wr_gf_pipe[0:1];
reg wr_bf_pipe[0:1];
reg frame_INfifo;

reg  [11:0] rd12b_addr;
wire rd_addrInc_w;
reg rd_addrReload;
wire [7:0] rddata8b_bramU_w;
wire [7:0] rddata8b_bramL_w;
reg [7:0] rddata8b_pipeU;
reg [7:0] rddata8b_pipeL;
reg [7:0] rddata8b_pipe;
wire [0:0] rd_eof_bramU_w;
wire [0:0] rd_eof_bramL_w;
reg rd_en;
reg rd_bramU;
reg rd_bramU_follow;
reg rd_pull_frame;
reg rd_eof;

reg wr_store_frameTog = 1'b0;
wire rd_store_frameSync_w;

reg rd_store_frameDelay = 1'b0;
reg rd_store_frame;
reg [8:0] rd9b_frames;
reg wr_fifo_full;

reg [1:0] old2b_rd_addr;
reg update_addrTog;
wire update_addrTogSync_w;
reg update_addrTogSync;

reg [11:0] wr12b_rd_addr;
wire [12:0] wr13b_addrDiff_in_w;
reg [11:0] wr12b_addrDiff;

reg [3:0] wr4b_fifoStatus;
reg rd_eofN_int;
reg [1:0] rd2b_valid_pipe;

//----------------------------------------------------------------------------
// Read State machines and control
//----------------------------------------------------------------------------

// local link state machine
// states are WAIT, QUEUE1, QUEUE2, QUEUE3, SOF, DATA, EOF
// clock state to next state

always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd3b_sm <= WAIT_s;
  end
  else begin
    rd3b_sm <= rd3b_nxt_sm;
  end
end

assign rd_eofN_o = rd_eofN_int;

// decode next state, combinatorial
always@(rd3b_sm or frame_INfifo or rd_eof or rd_dst_rdyN_i or
    rd_eofN_int or rd2b_valid_pipe) begin
  case(rd3b_sm)
    WAIT_s : begin
      // wait till there is a full frame in the fifo
      // then start to load the pipeline
      if(frame_INfifo == 1'b1 && rd_eofN_int == 1'b1) begin
         rd3b_nxt_sm <= QUEUE1_s;
      end
      else begin
        rd3b_nxt_sm <= WAIT_s;
      end
    end

    QUEUE1_s : begin
      // load the output pipeline
      // this takes three clocks
      rd3b_nxt_sm <= QUEUE2_s;
    end

    QUEUE2_s : begin
      rd3b_nxt_sm <= QUEUE3_s;
    end

    QUEUE3_s : begin
      rd3b_nxt_sm <= QUEUE_SOF_s;
    end

    QUEUE_SOF_s : begin
      // used mark sof at end of queue
      rd3b_nxt_sm <= DATA_s;  // move straight to frame.
    end

    SOF_s : begin
      // used to mark sof when following straight from eof
      if(rd_dst_rdyN_i == 1'b0) begin
         rd3b_nxt_sm <= DATA_s;
      end
      else begin
         rd3b_nxt_sm <= SOF_s;
      end
    end

    DATA_s : begin
      // When the eof marker is detected from the BRAM output
      // move to EOF state
      if(rd_dst_rdyN_i == 1'b0 && rd_eof == 1'b1) begin
         rd3b_nxt_sm <= EOF_s;
      end
      else begin
         rd3b_nxt_sm <= DATA_s;
      end
    end

    EOF_s : begin
      // hold in this state until dst rdy is low
      // and eof bit is accepted on interface
      // If there is a frame in the fifo, then the next frame
      // will already be queued into the pipe line so move straight
      // to sof state.
      if(rd_dst_rdyN_i == 1'b0) begin
         if(rd2b_valid_pipe[1] == 1'b1) begin
           rd3b_nxt_sm <= SOF_s;
         end
         else begin
           rd3b_nxt_sm <= WAIT_s;
         end
      end
      else begin
        rd3b_nxt_sm <= EOF_s;
      end
    end

    default : begin
      rd3b_nxt_sm <= WAIT_s;
    end
  endcase
end

// detect if frame in fifo was high 3 reads ago
// this is used to ensure we only treat data in the pipeline as valid if
// frame in fifo goes high at or before the eof of the current frame
// It may be that there is valid data (i.e a partial packet has been written)
// but until the end of that packet we do not know if it is a good packet
always@(posedge rd_clk_i) begin
  if(rd_dst_rdyN_i == 1'b0) begin
    rd2b_valid_pipe <= {rd2b_valid_pipe[0], frame_INfifo};
  end
end

// decode the output signals depending on current state.
// decode sof signal.
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_sofN_o <= 1'b1;
  end
  else begin
    case(rd3b_sm)
      QUEUE_SOF_s :
        // no need to wait for dst rdy to be low, as there is valid data
        rd_sofN_o <= 1'b0;
      SOF_s :
        // needed to wait till rd_dst_rdy is low to ensure eof signal has
        // been accepted onto the interface before asserting sof.
        if(rd_dst_rdyN_i == 1'b0) begin
          rd_sofN_o <= 1'b0;
        end
      default :
        // needed to wait till rd_dst_rdy is low to ensure sof signal has
        // been accepted onto the interface.
        if(rd_dst_rdyN_i == 1'b0) begin
          rd_sofN_o <= 1'b1;
        end
    endcase
  end
end

// decode eof signal
// check init value of this reg is 1.
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_eofN_int <= 1'b1;
  end
  else if(rd_dst_rdyN_i == 1'b0) begin
    // needed to wait till rd_dst_rdy is low to ensure penultimate byte of
    // frame has been accepted onto the interface before asserting eof and
    // that eof is accepted before moving on
    case(rd3b_sm)
      EOF_s :
        rd_eofN_int <= 1'b0;
      default :
        rd_eofN_int <= 1'b1;
    endcase
    // queue sof is not needed if init value is 1
  end
end

// decode data output
always@(posedge rd_clk_i) begin
  if(rd_en == 1'b1) begin
    rddata8b_o <= rddata8b_pipe;
  end
end

// decode the output scr_rdy signal
// want to remove the dependancy of src_rdy from dst rdy
// check init value of this reg is 1'b1
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_src_rdyN_o <= 1'b1;
  end
  else begin
    case(rd3b_sm)
      QUEUE_SOF_s :
        rd_src_rdyN_o <= 1'b0;
      SOF_s :
        rd_src_rdyN_o <= 1'b0;
      DATA_s :
        rd_src_rdyN_o <= 1'b0;
      EOF_s :
        rd_src_rdyN_o <= 1'b0;
      default :
        if(rd_dst_rdyN_i == 1'b0) begin
          rd_src_rdyN_o <= 1'b1;
        end
    endcase
  end
end

// decode internal control signals
// rd_en is used to enable the BRAM read and load the output pipe
always@(rd3b_sm or rd_dst_rdyN_i) begin
  case(rd3b_sm)
    WAIT_s :
      rd_en <= 1'b0;
    QUEUE1_s :
      rd_en <= 1'b1;
    QUEUE2_s :
      rd_en <= 1'b1;
    QUEUE3_s :
      rd_en <= 1'b1;
    QUEUE_SOF_s :
      rd_en <= 1'b1;
    default :
      rd_en <= !rd_dst_rdyN_i;
  endcase
end

// rd_addrInc_w is used to enable the BRAM read address to increment
assign rd_addrInc_w = rd_en;

// When the current frame is output, if there is no frame in the fifo, then
// the fifo must wait until a new frame is written in.  This requires the read
// address to be moved back to where the new frame will be written.  The pipe
// is then reloaded using the QUEUE states
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1)
    rd_addrReload <= 1'b0;
  else
    if(rd3b_sm == EOF_s && rd3b_nxt_sm == WAIT_s)
      rd_addrReload <= 1'b1;
    else
      rd_addrReload <= 1'b0;
end

// Data is available if there is at leat one frame stored in the FIFO.
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    frame_INfifo <= 1'b0;
  end
  else begin
    if(rd9b_frames != 9'b0) begin
      frame_INfifo <= 1'b1;
    end
    else begin
      frame_INfifo <= 1'b0;
    end
  end
end

// when a frame has been stored need to convert to rd clock domain for frame
// count store.
sync_block resync_wr_store_frame_tog (
.clk_i(rd_clk_i),
.data_i(wr_store_frameTog),
.data_o(rd_store_frameSync_w)
);

always@(posedge rd_clk_i) begin
  rd_store_frameDelay <= rd_store_frameSync_w;
end

// edge detect of the resynchronized frame count
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_store_frame <= 1'b0;
  end
  else begin
    // edge detector
    if((rd_store_frameDelay ^ rd_store_frameSync_w) == 1'b1) begin
       rd_store_frame <= 1'b1;
    end
    else begin
      rd_store_frame <= 1'b0;
    end
  end
end

always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_pull_frame <= 1'b0;
  end
  else begin
    if(rd3b_sm == SOF_s && rd3b_nxt_sm != SOF_s) begin
      rd_pull_frame <= 1'b1;
    end
    else if(rd3b_sm == QUEUE_SOF_s && rd3b_nxt_sm != QUEUE_SOF_s) begin
      rd_pull_frame <= 1'b1;
    end
    else begin
      rd_pull_frame <= 1'b0;
    end
  end
end

// Up/Down counter to monitor the number of frames stored within the
// the FIFO. Note:
//   * decrements at the beginning of a frame read cycle
//   * increments at the end of a frame write cycle
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd9b_frames <= 9'b0;
  end
  else begin
    // A frame is written to the fifo in this cycle, and no frame is being
    // read out on the same cycle
    if(rd_store_frame == 1'b1 && rd_pull_frame == 1'b0) begin
       rd9b_frames <= rd9b_frames + 1;
    end
    // A frame is being read out on this cycle and no frame is being
    // written on the same cycle
    else if(rd_store_frame == 1'b0 && rd_pull_frame == 1'b1) begin
       rd9b_frames <= rd9b_frames - 1;
    end
  end
end

//----------------------------------------------------------------------------
// Write State machines and control
//----------------------------------------------------------------------------

// write state machine
// states are IDLE, FRAME, EOF, GF, BF, OVFLOW
// clock state to next state
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr3b_sm <= IDLE_s;
  end
  else if(wr_enable_i == 1'b1) begin
    wr3b_sm <= wr3b_nxt_sm;
  end
end

// decode next state, combinatorial
always@(wr3b_sm or wr_dv_pipe[1] or wr_gf_pipe[1] or wr_bf_pipe[1]
      or wr_eof_bram[0] or wr_fifo_full) begin
  case(wr3b_sm)
    IDLE_s : begin
      // there is data in the incoming pipeline when dv_pipe(1) goes high
      if(wr_dv_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= FRAME_s;
      end
      else begin
        wr3b_nxt_sm <= IDLE_s;
      end
    end

    FRAME_s : begin
      // if fifo is full then go to overflow_o state.
      // if the good or bad flag is detected the end
      // of the frame has been reached!
      // this transistion occurs when the gb flag
      // is on the clock edge immediately following
      // the end of the frame.
      // if the eof_bram signal is detected then data valid has
      // fallen low and the end of frame has been detected.
      if(wr_fifo_full == 1'b1) begin
        wr3b_nxt_sm <= OVFLOW_s;
      end
      else if(wr_gf_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= GF_s;
      end
      else if(wr_bf_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= BF_s;
      end
      else if(wr_eof_bram[0] == 1'b1) begin
        wr3b_nxt_sm <= END_s;
      end
      else begin
        wr3b_nxt_sm <= FRAME_s;
      end
    end

    END_s : begin
      // if frame is full then go to overflow_o state
      // else wait until the good or bad flag has been received.
      if(wr_gf_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= GF_s;
      end
      else if(wr_bf_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= BF_s;
      end
      else begin
        wr3b_nxt_sm <= END_s;
      end
    end

    GF_s : begin
      // wait for next frame
      wr3b_nxt_sm <= IDLE_s;
    end

    BF_s : begin
      // wait for next frame
      wr3b_nxt_sm <= IDLE_s;
    end

    OVFLOW_s : begin
      // wait until the good or bad flag received.
      if(wr_gf_pipe[1] == 1'b1 || wr_bf_pipe[1] == 1'b1) begin
        wr3b_nxt_sm <= IDLE_s;
      end
      else begin
        wr3b_nxt_sm <= OVFLOW_s;
      end
    end

    default : begin
      wr3b_nxt_sm <= IDLE_s;
    end
  endcase
end

// decode control signals
// wr_en_w is used to enable the BRAM write and loading of the input pipeline
assign wr_en_w = (wr3b_sm == FRAME_s) ? 1'b1 : 1'b0;

// the upper and lower signals are used to distinguish between the upper and
// lower BRAM
assign wr_enL_w = wr_en_w & !wr12b_addr[11];
assign wr_enU_w = wr_en_w & wr12b_addr[11];

// increment the write address when we are receiving a frame
assign wr_addrInc_w = (wr3b_sm == FRAME_s) ? 1'b1 : 1'b0;

// if the fifo overflows or a frame is to be dropped, we need to move the
// write address back to the start of the frame.  This allows the data to be
// overwritten.
assign wr_addrReload_w = (wr3b_sm == BF_s || wr3b_sm == OVFLOW_s)
               ? 1'b1 : 1'b0;

// the start address is saved when in the WAIT state
assign wr_startAddrLoad_w = (wr3b_sm == IDLE_s) ? 1'b1 : 1'b0;

// we need to know when a frame is stored, in order to increment the count of
// frames stored in the fifo.
always@(posedge wr_clk_i) begin  // process
  if(wr_enable_i == 1'b1) begin
    if(wr3b_sm == GF_s) begin
      wr_store_frameTog <= ! wr_store_frameTog;
    end
  end
end

//----------------------------------------------------------------------------
// Address counters
//----------------------------------------------------------------------------

// write address is incremented when write enable signal has been asserted
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr12b_addr <= 12'b0;
  end
  else if(wr_enable_i == 1'b1) begin
    if(wr_addrReload_w == 1'b1) begin
      wr12b_addr <= wr12b_startAddr;
    end
    else if(wr_addrInc_w == 1'b1) begin
      wr12b_addr <= wr12b_addr + 1;
    end
  end
end

// store the start address
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr12b_startAddr <= 12'b0;
  end
  else if(wr_enable_i == 1'b1) begin
    if(wr_startAddrLoad_w == 1'b1) begin
      wr12b_startAddr <= wr12b_addr;
    end
  end
end

// read address is incremented when read enable signal has been asserted
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd12b_addr <= 12'b0;
  end
  else begin
    if(rd_addrReload == 1'b1) begin
      rd12b_addr <= rd12b_addr - 3;
    end
    else if(rd_addrInc_w == 1'b1) begin
      rd12b_addr <= rd12b_addr + 1;
    end
  end
end

// which BRAM is read from is dependant on the upper bit of the address
// space.  this needs to be registered to give the correct timing.
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    rd_bramU <= 1'b0;
    rd_bramU_follow <= 1'b0;
  end
  else if(rd_addrInc_w == 1'b1) begin
    rd_bramU <= rd12b_addr[11];
    rd_bramU_follow <= rd_bramU;
  end
end

//----------------------------------------------------------------------------
// Data Pipelines
//----------------------------------------------------------------------------

// register data inputs to bram
// no reset to allow srl16 target
always@(posedge wr_clk_i) begin
  if(wr_enable_i == 1'b1) begin
    wr8b_data_pipe[0] <= rxdata8b_i;
    wr8b_data_pipe[1] <= wr8b_data_pipe[0];
    wr8b_data_bram   <= wr8b_data_pipe[1];
  end
end

// no reset to allow srl16 target
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr_dv_pipe[0] <= 0;
    wr_dv_pipe[1] <= 0;
    wr_eof_bram  <= 0;
  end
  else if(wr_enable_i == 1'b1) begin
    wr_dv_pipe[0] <= rxdata_valid_i;
    wr_dv_pipe[1] <= wr_dv_pipe[0];
    wr_eof_bram[0] <= wr_dv_pipe[1] & !wr_dv_pipe[0];
  end
end

// no reset to allow srl16 target
always@(posedge wr_clk_i) begin
  if(wr_enable_i == 1'b1) begin
    wr_gf_pipe[0] <= rx_goodFrame_i;
    wr_gf_pipe[1] <= wr_gf_pipe[0];
    wr_bf_pipe[0] <= rx_badFrame_i;
    wr_bf_pipe[1] <= wr_bf_pipe[0];
  end
end

// register data outputs from bram
// no reset to allow srl16 target
always@(posedge rd_clk_i) begin
  if(rd_en == 1'b1) begin
    rddata8b_pipeU <= rddata8b_bramU_w;
    rddata8b_pipeL <= rddata8b_bramL_w;
    if(rd_bramU_follow == 1'b1) begin
      rddata8b_pipe <= rddata8b_pipeU;
    end
    else begin
      rddata8b_pipe <= rddata8b_pipeL;
    end
  end
end

// register data outputs from bram
always@(posedge rd_clk_i) begin
  if(rd_en == 1'b1) begin
    if(rd_bramU == 1'b1) begin
      rd_eof <= rd_eof_bramU_w[0];
    end
    else begin
      rd_eof <= rd_eof_bramL_w[0];
    end
  end
end

//----------------------------------------------------------------------------
// Overflow functionality
//----------------------------------------------------------------------------

// to minimise the number of read address updates the bottom 6 bits of the 
// read address are not passed across and the write domain will only sample 
// them when bits 5 and 4 of the read address transition from 01 to 10.  
// Since this is for full detection this just means that if the read stops
// the write will hit full up to 64 locations early

// need to use two bits and look for an increment transition as reload can cause
// a decrement on this boundary (decrement is only by 3 so above bit 2 should be safe)
always@(posedge rd_clk_i) begin
  if(rd_sreset_i == 1'b1) begin
    old2b_rd_addr <= 2'b00;
    update_addrTog <= 1'b0;
  end
  else begin
    old2b_rd_addr <= rd12b_addr[5:4];
    if(rd12b_addr[5:4] == 2'b10 & old2b_rd_addr == 2'b01) begin
       update_addrTog <= !update_addrTog;
    end
  end
end

sync_block sync_rd_addr_tog (
.clk_i(wr_clk_i),
.data_i(update_addrTog),
.data_o(update_addrTogSync_w)
);

// Convert the synchronized read address pointer gray code back to binary.
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    update_addrTogSync <= 1'b0;
    wr12b_rd_addr <= 12'd0;
  end
  else begin
    update_addrTogSync <= update_addrTogSync_w;
    if(update_addrTogSync ^ update_addrTogSync_w) begin
      wr12b_rd_addr <= {rd12b_addr[11:6], 6'd0};
    end
  end
end
  
assign wr13b_addrDiff_in_w = {1'b0,wr12b_rd_addr} - {1'b0,wr12b_addr};

// Obtain the difference between write and read pointers.
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr12b_addrDiff <= 12'b0;
  end
  else begin
    wr12b_addrDiff <= wr13b_addrDiff_in_w[11:0];
  end
end

// Detect when the FIFO is full
// The FIFO is considered to be full if the write address
// pointer is within 0 to 3 of the read address pointer.
always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr_fifo_full <= 1'b0;
  end
  else if(wr_enable_i == 1'b1) begin
    if(wr12b_addrDiff[11:4] == 8'b0 && wr12b_addrDiff[3:2] != 2'b0) begin
      wr_fifo_full <= 1'b1;
    end
    else begin
      wr_fifo_full <= 1'b0;
    end
  end
end

assign overflow_o = (wr3b_sm == OVFLOW_s) ? 1'b1 : 1'b0;

//----------------------------------------------------------------------------
// FIFO Status Signals
//----------------------------------------------------------------------------

// The FIFO status signal is four bits which represents the occupancy
// of the FIFO in 16'ths.  To generate this signal we therefore only
// need to compare the 4 most significant bits of the write address
// pointer with the 4 most significant bits of the read address
// pointer.

// already have fifo status on write side through wr12b_addrDiff.
// calculate fifo status here and output on the wr clock domain.

always@(posedge wr_clk_i) begin
  if(wr_sreset_i == 1'b1) begin
    wr4b_fifoStatus <= 4'b0;
  end
  else if(wr_enable_i == 1'b1) begin
    if(wr12b_addrDiff == 12'b0) begin
      wr4b_fifoStatus <= 4'b0;
    end
    else begin
      wr4b_fifoStatus[3] <= !wr12b_addrDiff[11];
      wr4b_fifoStatus[2] <= !wr12b_addrDiff[10];
      wr4b_fifoStatus[1] <= !wr12b_addrDiff[9];
      wr4b_fifoStatus[0] <= !wr12b_addrDiff[8];
    end
  end
end

assign rx4b_fifoStatus_o = wr4b_fifoStatus;

//----------------------------------------------------------------------------
// Instantiate Memory
//----------------------------------------------------------------------------
bram ramgen_rxl ( 
.doa(),    //no use
.cea(1'b1),
.dia({wr_eof_bram,wr8b_data_bram}), 
.addra(wr12b_addr[10:0]), 
.clka(wr_clk_i), 
.wea(wr_enL_w), 
//.rsta(wr_sreset_i), 
.dob({rd_eof_bramL_w,rddata8b_bramL_w}), 
.dib(9'b0),   //no use
.addrb(rd12b_addr[10:0]), 
.clkb(rd_clk_i), 
.web(1'b0), 
.ceb(rd_en)
//.rstb(rd_sreset_i)
);

bram ramgen_rxu ( 
.doa(),    //no use 
.cea(1'b1),
.dia({wr_eof_bram,wr8b_data_bram}), 
.addra(wr12b_addr[10:0]), 
.clka(wr_clk_i), 
.wea(wr_enU_w), 
//.rsta(wr_sreset_i), 
.dob({rd_eof_bramU_w,rddata8b_bramU_w}), 
.dib(9'b0),   //no use
.addrb(rd12b_addr[10:0]), 
.clkb(rd_clk_i), 
.web(1'b0),
.ceb(rd_en)
//.rstb(rd_sreset_i)
);

endmodule